package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"net/http"
	"sync"
	"time"

	"github.com/SkyAPM/go2sky"
	tracerestful "github.com/SkyAPM/go2sky-plugins/go-restful"
	http2 "github.com/SkyAPM/go2sky/plugins/http"
	"github.com/SkyAPM/go2sky/reporter"
	"github.com/emicklei/go-restful/v3"
)

func main() {
	ws := new(restful.WebService)
	ws.Filter(tracerestful.NewTraceFilterFunction(getTracer()))
	ws.Route(ws.GET("/hello").To(hello1Handler))
	ws.Route(ws.GET("/bye").To(bye1Handler))
	restful.Add(ws)

	_ = http.ListenAndServe(":18080", nil)
}

var (
	tracer *go2sky.Tracer
	mu     sync.Mutex
)

func getTracer() *go2sky.Tracer {
	if tracer != nil {
		return tracer
	}
	mu.Lock()
	defer mu.Unlock()
	if tracer != nil {
		return tracer
	}

	re, err := reporter.NewGRPCReporter("localhost:11800")
	if err != nil {
		log.Fatalf("new reporter error %v \n", err)
	}

	tracerTemp, err := go2sky.NewTracer("demo-service-alpha", go2sky.WithReporter(re), go2sky.WithInstance(IPV4()))
	if err != nil {
		log.Fatalf("create tracer error %v \n", err)
	}

	tracer = tracerTemp
	return tracer
}

func hello1Handler(req *restful.Request, resp *restful.Response) {
	time.Sleep(time.Duration(80+rand.Intn(20)) * time.Millisecond)

	//获取带有entry span的context
	helloReq, err := http.NewRequestWithContext(req.Request.Context(), http.MethodGet, "http://localhost:18081/hello", nil)
	if err != nil {
		panic(err)
	}
	helloResp, err := getHttpClient().Do(helloReq)
	if err != nil {
		fmt.Println(err)
		resp.WriteHeader(http.StatusInternalServerError)
		resp.Write([]byte("request error"))
		return
	}
	defer helloResp.Body.Close()
	bs, err := ioutil.ReadAll(helloResp.Body)
	if err != nil {
		fmt.Println(err)
		resp.WriteHeader(http.StatusInternalServerError)
		resp.Write([]byte("request error"))
		return
	}

	resp.WriteHeader(http.StatusOK)
	resp.Write(bs)
}

func bye1Handler(req *restful.Request, resp *restful.Response) {
	time.Sleep(time.Duration(80+rand.Intn(20)) * time.Millisecond)

	//获取带有entry span的context
	byeReq, err := http.NewRequestWithContext(req.Request.Context(), http.MethodGet, "http://localhost:18081/bye", nil)
	if err != nil {
		panic(err)
	}

	byeResp, err := getHttpClient().Do(byeReq)
	if err != nil {
		fmt.Println(err)
		resp.WriteHeader(http.StatusInternalServerError)
		resp.Write([]byte("request error"))
		return
	}
	defer byeResp.Body.Close()
	bs, err := ioutil.ReadAll(byeResp.Body)
	if err != nil {
		fmt.Println(err)
		resp.WriteHeader(http.StatusInternalServerError)
		resp.Write([]byte("request error"))
		return
	}

	resp.WriteHeader(http.StatusOK)
	resp.Write(bs)
}

var (
	client *http.Client
	lock   sync.Mutex
)

func getHttpClient() *http.Client {
	if client != nil {
		return client
	}
	lock.Lock()
	defer lock.Unlock()
	if client != nil {
		return client
	}

	clientWithTracer, err := http2.NewClient(getTracer())
	if err != nil {
		log.Fatalf("create client error %v \n", err)
	}
	client = clientWithTracer
	return client
}
